package org.greatlogic.gwtfilereaderwidget.client.itunes;

import com.google.gwt.xml.client.Element;
import java.util.TreeSet;
import org.greatlogic.gwtfilereaderwidget.client.itunes.ITunesEnums.ETrackKeyDataType;
import org.greatlogic.gwtfilereaderwidget.client.itunes.ITunesEnums.ETrackKeyType;

public class KeyAndValueEntry {
//--------------------------------------------------------------------------------------------------
public static final KeyAndValueEntry EmptyKeyAndValueEntry;
private static TreeSet<String>       _unknownKeyDataTypeSet;
private static TreeSet<String>       _unknownKeyTypeSet;

private ETrackKeyDataType                 _keyDataType;
private ETrackKeyType                     _keyType;
private String                       _rawValue;
private boolean                      _valueAsBoolean;
private long                         _valueAsLong;
private String                       _valueAsString;
private boolean                      _valueConverted;
//--------------------------------------------------------------------------------------------------
static {
  EmptyKeyAndValueEntry = new KeyAndValueEntry(ETrackKeyType.Unknown, ETrackKeyDataType.Unknown, "");
  _unknownKeyDataTypeSet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
  _unknownKeyTypeSet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
} // static initializer
//--------------------------------------------------------------------------------------------------
/**
 * Creates KeyAndValueEntry objects using the elements and values that are returned from a stream
 * reader. Examples:
 * <key>Integer value</key><integer>1234</integer>
 * <key>String value</key><string>string value</string>
 * <key>Boolean value</key><true/>
 * @param parent The object that will contain the KeyAndValueEntry objects that are created (for
 * example, the Track or Playlist object).
 * @param keyAndValueParentElement The parent element to the "key" and value elements.
 */
static void createFromKeyAndValueParentNode(final IHasKeyAndValueEntries parent,
                                            final Element keyAndValueParentElement)
  throws ITunesException {
  Element keyTypeElement = ITunesUtil.getFirstChildElement(keyAndValueParentElement, "key");
  while (keyTypeElement != null) {
    String keyTypeString = ITunesUtil.getElementValue(keyTypeElement);
    ETrackKeyType keyType = ETrackKeyType.lookupUsingElementValue(keyTypeString);
    if (keyType == null) {
      _unknownKeyTypeSet.add(keyTypeString);
    }
    Element keyDataTypeElement = ITunesUtil.getNextSiblingElement(keyTypeElement);
    String keyDataTypeTag = keyDataTypeElement.getNodeName();
    ETrackKeyDataType keyDataType = ETrackKeyDataType.lookup(keyDataTypeTag);
    String value = null;
    switch (keyDataType) {
      case Array:
        if (!parent.processArray(keyType, keyDataTypeElement)) {
          {
          } // todo: error
        }
        break;
      case Boolean:
        value = keyDataTypeTag;
        break;
      case Unknown:
        _unknownKeyDataTypeSet.add(keyDataTypeTag);
        break;
      default:
        value = ITunesUtil.getElementValue(keyDataTypeElement);
        break;
    }
    if (keyType != null && value != null) {
      KeyAndValueEntry keyAndValueEntry = new KeyAndValueEntry(keyType, keyDataType, value);
      parent.addKeyAndValueEntry(keyAndValueEntry);
    }
    keyTypeElement = ITunesUtil.getNextSiblingElement(keyTypeElement, "key");
  }
} // createFromKeyAndValueParentNode()
//--------------------------------------------------------------------------------------------------
public static TreeSet<String> getUnknownKeyDataTypeSet() {
  return _unknownKeyDataTypeSet;
} // getUnknownKeyDataTypeSet()
//--------------------------------------------------------------------------------------------------
public static TreeSet<String> getUnknownKeyTypeSet() {
  return _unknownKeyTypeSet;
} // getUnknownKeyTypeSet()
//--------------------------------------------------------------------------------------------------
KeyAndValueEntry(final ETrackKeyType keyType, final ETrackKeyDataType keyDataType, final String value) {
  _keyType = keyType;
  _keyDataType = keyDataType;
  _rawValue = value;
} // KeyAndValueEntry()
//--------------------------------------------------------------------------------------------------
private void convertRawValue() {
  if (_rawValue.contains("&#")) {
    _valueAsString = "";
    int hexIndex = 0;
    int prevIndex;
    do {
      prevIndex = hexIndex;
      hexIndex = _rawValue.indexOf('&', hexIndex);
      if (hexIndex > 0) {
        _valueAsString += _rawValue.substring(prevIndex, hexIndex);
        _valueAsString += (char)Integer.parseInt(_rawValue.substring(hexIndex + 2, hexIndex + 4));
        hexIndex += 5;
      }
    } while (hexIndex > 0);
    _valueAsString = _valueAsString +
                     (prevIndex < _rawValue.length() ? _rawValue.substring(prevIndex) : "");
  }
  else {
    _valueAsString = _rawValue;
  }
  _valueAsString = ITunesUtil.utf8Decode(_valueAsString, true).toString();
  if (_keyType.getKeyDataType() == ETrackKeyDataType.Date) {
    // todo: convert the _valueAsString to yyyymmddhhmmss
  }
  _valueAsBoolean = ITunesUtil.stringToBoolean(_valueAsString, false);
  _valueAsLong = ITunesUtil.stringToLong(_valueAsString, 0);
  _valueConverted = true;
} // convertRawValue()
//--------------------------------------------------------------------------------------------------
public ETrackKeyDataType getKeyDataType() {
  return _keyDataType;
} // getKeyDayaType()
//--------------------------------------------------------------------------------------------------
public ETrackKeyType getKeyType() {
  return _keyType;
} // getKeyType()
//--------------------------------------------------------------------------------------------------
public boolean getValueAsBoolean() {
  if (!_valueConverted) {
    convertRawValue();
  }
  return _valueAsBoolean;
} // getValueAsBoolean()
//--------------------------------------------------------------------------------------------------
public int getValueAsInt() {
  return (int)getValueAsLong();
} // getValueAsInt()
//--------------------------------------------------------------------------------------------------
public long getValueAsLong() {
  if (!_valueConverted) {
    convertRawValue();
  }
  return _valueAsLong;
} // getValueAsLong()
//--------------------------------------------------------------------------------------------------
public String getValueAsString() {
  if (!_valueConverted) {
    convertRawValue();
  }
  return _valueAsString;
} // getValueAsString()
//--------------------------------------------------------------------------------------------------
String getXML() {
  String result = "<key>" + _keyType.getElementValue() + "</key>";
  if (_keyType.getKeyDataType() == ETrackKeyDataType.Boolean) {
    result += "<" + _rawValue + "/>";
  }
  else {
    String tag = _keyType.getKeyDataType().name().toLowerCase();
    result += "<" + tag + ">" + ITunesUtil.escapeValue(_rawValue, false) + "</" + tag + ">";
  }
  return result;
} // getXML()
//--------------------------------------------------------------------------------------------------
@Override
public String toString() {
  return _keyType + "=" + _rawValue;
} // toString()
//--------------------------------------------------------------------------------------------------
}